package client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.user.client.ui.*;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Command;

/**
 * @author Ayzen
 * @version 1.0 29.04.2007 23:44:10
 */
public class Test implements EntryPoint {

  public static final String TAG =
          "<object id='test' width='0px' height='0px'>" +
          "  <param name='movie' value='text_sockets_test.swf'>" +
          "  <param name='play' value='false'>" +
          "  <param name='loop' value='false'>" +
          "  <param name='FlashVars' value='crossdomain={0}&id={1}'/>" +
          "  <embed name='test'" +
          "         src='text_sockets_test.swf'" +
          "         FlashVars='crossdomain={0}&id={1}'" +
          "         width='0px'" +
          "         height='0px'" +
          "         play='false'" +
          "         loop='false'" +
          "         swLiveConnect='true'" +
          "  </embed>" +
          "</object>";

  private HTML flashTag;
  private JavaScriptObject applet;
  
  /**
   * Fix for IE. IE couldn't pass data from Flash to JavaScript that exceeds 479 bytes, so wee need to divide data into
   * parts (each 470 bytes) and pass them to JavaScript.
   */
  private String data = "";

  private String host = "127.0.0.1:777";
  private boolean connected = false;

  private ScrollPanel scrollPanel;
  private VerticalPanel history = new VerticalPanel();
  private TextBox input = new TextBox();
  Label lblHost = new Label(" Server: " + host);

  public void onModuleLoad() {
    initGUI();
    initApplet();
  }

  private void initApplet() {
    Panel root = RootPanel.get();

    root.remove(flashTag);

    flashTag = new HTML();
    flashTag.setSize("0", "0");
    flashTag.setHTML(TAG.replaceAll("[{]0[}]", "xmlsocket://" + host).replaceAll("[{]1[}]", "1"));

    initFunctions(1);
    root.add(flashTag);
  }

  private void initGUI() {
    VerticalPanel mainPanel = new VerticalPanel();
    mainPanel.setBorderWidth(1);
    scrollPanel = new ScrollPanel(history);
    scrollPanel.setSize("600", "300");
    input.setWidth("600");

    HorizontalPanel controlPanel = new HorizontalPanel();
    Button btnSend = new Button("Send");
    Button btnConnect = new Button("Connect");
    Button btnDisconnect = new Button("Disconnect");
    Button btnChangeServer = new Button("Change server");
    controlPanel.add(btnSend);
    controlPanel.add(btnConnect);
    controlPanel.add(btnDisconnect);
    controlPanel.add(btnChangeServer);
    controlPanel.add(lblHost);

    input.addKeyboardListener(new KeyboardListenerAdapter(){
      public void onKeyPress(Widget sender, char keyCode, int modifiers) {
        if (keyCode == KeyboardListener.KEY_ENTER)
          sendMessage();
      }
    });

    btnSend.addClickListener(new ClickListener() {
      public void onClick(Widget sender) {
        sendMessage();
      }
    });

    btnConnect.addClickListener(new ClickListener() {
      public void onClick(Widget sender) {
        println(" ** Connecting to server...");
        connectImpl(host);
      }
    });

    btnDisconnect.addClickListener(new ClickListener() {
      public void onClick(Widget sender) {
        if (connected) {
          connected = false;
          println(" ** Disconnected from server.");
          disconnectImpl();
        }
        else
          println(" ** Not connected to server.");
      }
    });

    btnChangeServer.addClickListener(new ClickListener() {
      public void onClick(Widget sender) {
        host = inputText("Enter server ip:port", host);
        if (connected) {
          connected = false;
          println(" ** Disconnected from server.");
          disconnectImpl();
        }
        lblHost.setText(" Server: " + host);
        getPolicyFileImpl(host);
      }
    });

    mainPanel.add(scrollPanel);
    mainPanel.add(input);
    mainPanel.add(controlPanel);

    RootPanel.get().add(mainPanel);

    println("Welcome to Sockets test application :)");
  }

  private void sendMessage() {
    if (connected) {
      String data = input.getText();
      input.setText("");
      sendImpl(data);
      println(" >> " + data);
    }
    else {
      println(" ** " + "Not connected to server.");
    }
  }

  private void println(String message) {
    history.add(new Label(message));
    scrollToBottom();
  }

  public void scrollToBottom() {
    scrollToBottomImpl(scrollPanel.getElement());
  }

  private native void scrollToBottomImpl(Element element) /*-{
    element.scrollTop = element.scrollHeight;
  }-*/;

  private void onConnect() {
    connected = true;
    println(" ** Connected to server.");
  }

  private void onData(String data) {
    println(" << " + data);
  }

  private void onClose() {
    println(" ** Server closed connection.");
    connected = false;
  }

  private void onIOError(String message) {
    println(" ** Input/output error: " + message + ".");
  }

  private native String inputText(String message, String defText)/*-{
    var text = prompt(message, defText);
    if (text != null && text != "")
      return text;
    else
      return defText;
  }-*/;

  // Functions for Flash support

  private native void initFunctions(int id)/*-{
    var instance = this;
                   
    $wnd["flash_" + id + "_onAppletLoad"] = function(applet) {
      instance.@client.Test::applet = $doc["test"];
   }
    $wnd["flash_" + id + "_onConnect"] = function() {
      instance.@client.Test::onConnect()();
    }
    $wnd["flash_" + id + "_onClose"] = function() {
      instance.@client.Test::onClose()();
    }
    $wnd["flash_" + id + "_onData"] = function(data) {
      if (instance.@client.Test::applet === null)
        $wnd["flash_" + id + "_onAppletLoad"]();
      else {
        var toPass = instance.@client.Test::data + data;
        instance.@client.Test::data = "";
        instance.@client.Test::onData(Ljava/lang/String;)(toPass);
        instance.@client.Test::applet.SetVariable("ready", "");
      }
    }
    $wnd["flash_" + id + "_onPart"] = function(data) {
      instance.@client.Test::data += data;
      instance.@client.Test::applet.SetVariable("ready", "");
    }
    $wnd["flash_" + id + "_onIOError"] = function(msg) {
      instance.@client.Test::onIOError(Ljava/lang/String;)(msg);
    }
  }-*/;

  private native void connectImpl(String server)/*-{
    this.@client.Test::applet.SetVariable("connect", server);
  }-*/;

  private native void disconnectImpl()/*-{
    this.@client.Test::applet.SetVariable("close", "");
  }-*/;

  private native void sendImpl(String data)/*-{
    this.@client.Test::applet.SetVariable("send", data);
  }-*/;

  private native void getPolicyFileImpl(String url)/*-{
    this.@client.Test::applet.SetVariable("crossdomain", url);
  }-*/;

}
